﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using InkFx.WinControl.Core;
using InkFx.WinControl.Theme;
using InkFx.WinControl.Utils;
using DA = InkFx.WinControl.XIDEAlignment;
using DTG = InkFx.WinControl.XIDEGroup;
using DTGS = InkFx.WinControl.XIDEGroupState;
using DTGP = InkFx.WinControl.XIDEPage;
using DTGPR = InkFx.WinControl.XIDEPageGRect;
using DTGB = InkFx.WinControl.XIDEButton;

namespace InkFx.WinControl
{
    /// <summary>
    /// 提供一个可用来创建其他控件的空控件。
    /// </summary>
    [ToolboxItem(false)]
    public class XIDEGroup : XIDEUserControl
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="idePanel">Type: XIDEPanel</param>
        /// <param name="align">Type: XIDEAlignment</param>
        public XIDEGroup(XIDEPanel idePanel, XIDEAlignment align)
        {
            this.Name = XIDEPanel.NewName("ideGroup");
            this.m_IDEPanel = idePanel;
            this.m_Alignment = (align == DA.None) ? DA.Left : align;
            if (idePanel != null) idePanel.RegGroup(this);

            //base.BorderStyle = BorderStyle.FixedSingle;
            //this.Visible = false;
            Tools.LogDebug(string.Format("XIDEGroup 创建: Name='{0}' Type='{1}' ", this.Name, Tools.GetKnowTypeName(this.GetType())));
        }


        #region 字 段 属 性 事件

        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEPanel m_IDEPanel;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected internal XIDEAlignment m_Alignment = XIDEAlignment.Left;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected internal XIDEGroupState m_State = XIDEGroupState.Expand;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEPage m_ActivePage = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected List<XIDEPage> m_ListPage = new List<XIDEPage>();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventCloseClick = new object();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventRivetClick = new object();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventNormalClick = new object();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventMaximizeClick = new object();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventMenuStripClick = new object();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventStateChanged = new object();



        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public virtual XIDEAlignment Alignment
        {
            get { return m_Alignment; }
            //set
            //{
            //    if (m_Alignment == value) return;
            //    m_Alignment = value;
            //    if (m_Alignment == DA.Center && m_State == DTGS.Collapse) State = DTGS.Expand;
            //}
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public virtual XIDEPanel IDEPanel
        {
            get { return m_IDEPanel; }
        }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public virtual DTGS State
        {
            get { return m_State; }
            //set
            //{
            //    if (m_State == value) return;
            //    if (Alignment == DA.Center && value == DTGS.Collapse) { return; }
            //    SetState(value);
            //    //IDEPopPanel.TogglePopGroup(null);
            //}
        }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public List<XIDEPage> ListPage
        {
            get { return m_ListPage; }
        }


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public bool InCenterPanel
        {
            get
            {
                var idePanel = this.IDEPanel;
                if (idePanel == null) return false;
                var list = idePanel.FindListCenterGroup();
                return list.Contains(this);
            }
        }


        /// <summary>
        /// 获取或设置与此控件关联的文本。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public override string Text
        {
            get
            {
                var page = this.ActivePage;
                return page == null ? string.Empty : page.Text;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public XIDEPage ActivePage
        {
            get
            {
                if (m_ActivePage != null)
                {
                    if (m_ListPage.Contains(m_ActivePage)) { return m_ActivePage; }
                    else m_ActivePage = null;
                }
                return m_ListPage.Count >= 1 ? m_ListPage[0] : null;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public XIDEFrame ActiveFrame
        {
            get
            {
                var page = this.ActivePage;
                return page == null ? null : page.Frame;
            }
            set
            {
                if (value == null || value == this.ActiveFrame) return;
                var page = this.FindPage(value);
                if (page != null) this.SetAutoActivePage(page);
            }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示是否显示该控件及其所有父控件。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new bool Visible
        {
            get { return base.Visible; }
            set
            {
                if (this.Disposing || this.IsDisposed) return;
                base.Visible = value;
            }
        }
        /// <summary>
        /// 获取或设置一个值，该值指示是否显示该控件及其所有父控件。
        /// </summary>
        [Browsable(false), Obsolete("XIDEGroup不允许使用 Parent 属性", true), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new System.Windows.Forms.Control Parent
        {
            get { return base.Parent; }
            set { base.Parent = value; }
        }
        /// <summary>
        /// 获取或设置一个值，该值指示是否显示该控件及其所有父控件。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new System.Windows.Forms.Control BaseParent
        {
            get { return base.Parent; }
            set
            {
                //if (base.Parent != value) { Console.WriteLine(string.Format("Group {0} P: {1} > {2}", this.Name, (base.Parent == null ? "null" : base.Parent.Name), (value == null ? "null" : value.Name))); }
                base.Parent = value;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new DockStyle Dock
        {
            get { return base.Dock; }
            set { base.Dock = value; }
        }


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public event XIDEPageEventHandler CloseClick
        {
            add { base.Events.AddHandler(m_EventCloseClick, value); }
            remove { base.Events.RemoveHandler(m_EventCloseClick, value); }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public event EventHandler RivetClick
        {
            add { base.Events.AddHandler(m_EventRivetClick, value); }
            remove { base.Events.RemoveHandler(m_EventRivetClick, value); }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public event EventHandler StateChanged
        {
            add { base.Events.AddHandler(m_EventStateChanged, value); }
            remove { base.Events.RemoveHandler(m_EventStateChanged, value); }
        }


        #endregion



        /// <summary>
        /// 
        /// </summary>
        public const int CAPTION_HEIGHT = 23;
        /// <summary>
        /// 
        /// </summary>
        public const int CAPTION_BTN_SIZE = 17;
        /// <summary>
        /// 
        /// </summary>
        public const int MIN_SHOW_HEIGHT = 50;
        /// <summary>
        /// 
        /// </summary>
        public const int MIN_SHOW_WIDTH = 62;


        #region  坐 标 区 域

        /// <summary>
        /// 内部字段
        /// </summary>
        protected internal bool m_SizeIsSmall = false;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectTitle = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectText = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectClose = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectRivet = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectMinMax = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectMenuStrip = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectFullTabPage = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectBorber = Rectangle.Empty;

        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectTitle
        {
            get { return m_RectTitle; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectText
        {
            get { return m_RectText; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectClose
        {
            get { return m_RectClose; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectRivet
        {
            get { return m_RectRivet; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectMinMax
        {
            get { return m_RectMinMax; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectMenuStrip
        {
            get { return m_RectMenuStrip; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectFullTabPage
        {
            get { return m_RectFullTabPage; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectBorber
        {
            get { return m_RectBorber; }
        }


        /// <summary>
        /// 
        /// </summary>
        public void ResetRect()
        {
            if (this.IsCenterLayout())
                ResetCenterRect();
            else
                ResetNoCenterRect();

            //尺寸太小则不显示
            if (this.State == DTGS.Expand)
            {
                var bounds = this.Bounds;
                //var padding = base.Padding;
                var hide = bounds.Width <= 0 || bounds.Height <= 0;
                hide = hide || (bounds.Width < MIN_SHOW_WIDTH || bounds.Height < 0);
                this.m_SizeIsSmall = hide;
            }

            //将非激活Frame隐藏
            var frameA = this.ActiveFrame;
            foreach (var page in this.ListPage)
            {
                var frame = page.Frame;
                if (frame != null) frame.Visible = (frame == frameA);
            }

            var idePanel = this.IDEPanel;
            if (idePanel != null) idePanel.OnLayoutChanged(EventArgs.Empty);
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual void ResetCenterRect()
        {
            int border = this.BorderVisible ? 1 : 0;
            int pageCount = m_ListPage == null ? 0 : m_ListPage.Count;

            var size = this.Size;
            var rectTitle = new Rectangle(0, 0, size.Width, CAPTION_HEIGHT + border);
            m_RectTitle = Rectangle.Empty;
            m_RectText = Rectangle.Empty;
            m_RectClose = Rectangle.Empty;
            m_RectRivet = Rectangle.Empty;
            m_RectMinMax = Rectangle.Empty;
            m_RectMenuStrip = new Rectangle(rectTitle.Width - CAPTION_BTN_SIZE - (rectTitle.Height - CAPTION_BTN_SIZE) / 2, rectTitle.Y + (rectTitle.Height - CAPTION_BTN_SIZE) / 2, CAPTION_BTN_SIZE, CAPTION_BTN_SIZE);
            m_RectFullTabPage = new Rectangle(rectTitle.X, rectTitle.Y, rectTitle.Width, rectTitle.Height); //new Rectangle(0, 0, rectTitle.Width - 3 - m_RectMenuStrip.Width - 3, CAPTION_HEIGHT);
            m_RectBorber = new Rectangle(0, CAPTION_HEIGHT, size.Width, size.Height - rectTitle.Height + border);
            var padding = new Padding(border, CAPTION_HEIGHT + border, border, border);
            base.Padding = padding;


            int maxWidth = m_RectFullTabPage.Width - (3 + m_RectMenuStrip.Width + 3);
            if (m_ListPage != null)
            {
                #region  计算各个子Page的标题区域

                int fullWidth = 0;
                foreach (var page in m_ListPage) { fullWidth = fullWidth + page.FullWidth; }

                int x = m_RectFullTabPage.X;
                for (int i = 0, len = m_ListPage.Count; i < len; i++)
                {
                    var page = m_ListPage[i];
                    if (x + page.FullWidth <= maxWidth)
                    {
                        page.RectRealTitle = new Rectangle(x, m_RectFullTabPage.Y, page.FullWidth, m_RectFullTabPage.Height);
                    }
                    else
                    {
                        page.RectRealTitle = (i == 0) ? new Rectangle(x, m_RectFullTabPage.Y, maxWidth, m_RectFullTabPage.Height) : Rectangle.Empty;
                    }
                    x = x + page.FullWidth;
                }

                #endregion
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual void ResetNoCenterRect()
        {
            int border = this.BorderVisible ? 1 : 0;
            int pageCount = m_ListPage == null ? 0 : m_ListPage.Count;

            var size = this.Size;
            bool showTabPage = !(this.State == DTGS.Popup && XIDEPopPanel.ActivePopPage != null) && pageCount >= 2;
            m_RectTitle = new Rectangle(border, border, size.Width - border - border, CAPTION_HEIGHT);
            m_RectClose = new Rectangle(m_RectTitle.Width - CAPTION_BTN_SIZE - (m_RectTitle.Height - CAPTION_BTN_SIZE) / 2, m_RectTitle.Y + (m_RectTitle.Height - CAPTION_BTN_SIZE) / 2, CAPTION_BTN_SIZE, CAPTION_BTN_SIZE);
            m_RectRivet = new Rectangle(m_RectClose.X - 1 - m_RectClose.Width, m_RectClose.Y, m_RectClose.Width, m_RectClose.Height);
            m_RectMenuStrip = new Rectangle(m_RectRivet.X - 1 - m_RectRivet.Width, m_RectRivet.Y, m_RectRivet.Width, m_RectRivet.Height);
            m_RectText = new Rectangle(m_RectTitle.X + 3, m_RectTitle.Y, (Math.Min(Math.Min(m_RectMenuStrip.X, m_RectRivet.X), m_RectClose.X) - m_RectTitle.X - 3), m_RectTitle.Height);
            m_RectFullTabPage = (!showTabPage) ? Rectangle.Empty : new Rectangle(0, size.Height - CAPTION_HEIGHT - border, size.Width, CAPTION_HEIGHT + border);
            m_RectBorber = new Rectangle(0, 0, size.Width, (showTabPage ? (size.Height - m_RectFullTabPage.Height + border) : size.Height));
            base.Padding = new Padding(border, m_RectTitle.Bottom, border, (showTabPage ? (CAPTION_HEIGHT + border) : border));

            var floatForm = this.FindForm() as XIDEFloatForm;
            if (floatForm != null) { m_RectMinMax = m_RectRivet; m_RectRivet = Rectangle.Empty; }


            if (showTabPage && m_ListPage != null)
            {
                #region  计算各个子Page的标题区域

                int fullWidth = 0;
                int maxWidth = m_RectFullTabPage.Width;
                foreach (var page in m_ListPage) fullWidth = fullWidth + page.FullWidth;

                if (maxWidth >= fullWidth)
                {
                    int x = m_RectFullTabPage.X;
                    for (int i = 0, len = m_ListPage.Count; i < len; i++)
                    {
                        var page = m_ListPage[i];
                        page.RectRealTitle = new Rectangle(x, m_RectFullTabPage.Y, page.FullWidth, m_RectFullTabPage.Height);
                        x = x + page.FullWidth;
                    }
                }
                else
                {
                    int x = m_RectFullTabPage.X;
                    int width1 = maxWidth / m_ListPage.Count;
                    int width2 = width1 + maxWidth - (width1 * m_ListPage.Count);
                    for (int i = 0, len = m_ListPage.Count; i < len; i++)
                    {
                        var page = m_ListPage[i];
                        var width3 = (i >= len - 1) ? width2 : width1;
                        page.RectRealTitle = (i >= len - 1)
                            ? new Rectangle(x, m_RectFullTabPage.Y, width2, m_RectFullTabPage.Height)
                            : new Rectangle(x, m_RectFullTabPage.Y, width1, m_RectFullTabPage.Height);
                        x = x + width3;
                    }
                }

                #endregion
            }
            else if (m_ListPage != null)
            {
                #region  将各个子Page的标题区域 置为无效

                for (int i = 0, len = m_ListPage.Count; i < len; i++)
                {
                    var page = m_ListPage[i];
                    page.RectRealTitle = Rectangle.Empty;
                }

                #endregion
            }
        }



        /// <summary>
        /// 在布局上是否使用 中央布局模式 (此模式下, 所有Page选项卡 都在上面, 且会在右上角显示 下拉列表按钮)
        /// <para>一般 Alignment==Center 且 不浮动时 此函数返回true</para>
        /// </summary>
        /// <returns>如果使用中央布局 则返回 true</returns>
        public virtual bool IsCenterLayout()
        {
            var align = this.Alignment;
            if (align != DA.Center) return false;

            var floatForm = this.FindForm() as XIDEFloatForm;
            return floatForm == null;
        }

        #endregion


        #region  逻 辑 函 数

        //public void SetState(XIDEGroupState state)
        //{
        //    if (m_State == state) return;
        //    if (Alignment == DA.Center && (state == DTGS.Collapse || state == DTGS.Popup))
        //        throw new Exception("中央布局的控件不允许设置为 折叠或弹出 状态!");

        //    var oldState = m_State;
        //    m_State = state;

        //    bool dock = (oldState == DTGS.Expand || oldState == DTGS.Collapse);
            
        //    if (m_State == DTGS.Expand || m_State == DTGS.Collapse)
        //    {
        //        if (!dock) { this.ReleaseFloatForm(); }
        //        if (m_State == DTGS.Expand) { this.Visible = true; }
        //        else if (m_State == DTGS.Collapse) { this.Visible = false; }
        //    }


        //    OnStateChanged(EventArgs.Empty);
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group">Type: XIDEGroup</param>
        /// <param name="align">Type: DA</param>
        /// <returns></returns>
        public XIDEGroup DoDock(XIDEGroup group, DA align)
        {
            if (group == null || align == DA.None) return this;
            var idePanel = this.IDEPanel;
            if (idePanel == null) throw new ArgumentNullException("XIDEGroup.IDEPanel");

            XIDEGroup result = this;
            idePanel.TransLayout(() =>
            {
                #region  原区域拆分

                var ctrl1 = this;
                //if (!(ctrl1 is IDETabGroup)) throw new Exception(string.Format("只允许布局附着到 IDETabGroup 的控件下, 不允许附着到 类型为 '{0}' 的控件下!", ctrl1.GetType().FullName));
                //MessageBox.Show(ctrl.GetType().ToString() + " > " + ctrl1.GetType().ToString());

                if (align == DA.Center)
                {
                    //MessageBox.Show("中央增加控件: \r\n" + group.GetType().ToString() + " > " + ctrl1.GetType().ToString());

                    group.ReleaseSplitPanel();
                    group.m_Alignment = ctrl1.Alignment;
                    var ctrl0 = group;
                    ctrl1.MergeGroup(ctrl0);
                    //group.State = DTGS.Expand; //2020-07-30
                    idePanel.ActiveGroup = ctrl1;
                    result = ctrl1;
                }
                else
                {
                    XIDESplitControl.DoSplit(this, group, align);
                    idePanel.ActiveGroup = group;
                    result = group;
                }

                #endregion
            });

            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="frame">Type: XIDEFrame</param>
        /// <param name="align">Type: DA</param>
        /// <returns></returns>
        public XIDEGroup DoDock(XIDEFrame frame, DA align)
        {
            if (frame == null || align == DA.None) return this;
            var idePanel = this.IDEPanel;
            if (idePanel == null) throw new ArgumentNullException("XIDEGroup.IDEPanel");

            XIDEGroup group = new XIDEGroup(idePanel, align);
            frame.Dock = DockStyle.Fill;
            group.AppendPage(frame);
            return DoDock(group, align);
        }

        /// <summary>
        /// 将参数 group 中的所有 XIDEPage 都合并到当前 XIDEGroup 中
        /// <para>合并完成后, 参数 group 将会被释放</para>
        /// </summary>
        /// <param name="group">需要融入的 XIDEGroup</param>
        /// <returns></returns>
        public XIDEGroup MergeGroup(XIDEGroup group)
        {
            if (group == null || group == this) return this;
            var idePanel = this.IDEPanel;
            if (idePanel == null) throw new ArgumentNullException("XIDEGroup.IDEPanel");

            idePanel.TransLayout(() =>
            {
                var list = new List<XIDEPage>(group.m_ListPage);
                for (int i = list.Count - 1; i >= 0; i--) { var page = list[i]; AppendPage(page, 0, false); }
                group.Dispose();
                if (list.Count >= 1) SetActivePage(list[0]);
                idePanel.ActiveGroup = this;
                this.ResetRect();
                this.Invalidate();
            });

            return this;
        }
        /// <summary>
        /// 从当前 XIDEGroup 中, 将一个 XIDEPage 拖动出来 (即: 将 page 从当前Group中 分离出来)
        /// </summary>
        /// <param name="page">需要分离的 XIDEPage</param>
        /// <returns>分离出来的 XIDEPage 所在的 XIDEGroup</returns>
        public XIDEGroup SeparateGroup(XIDEPage page)
        {
            if (page == null) return this;
            var idePanel = this.IDEPanel;
            if (idePanel == null) throw new ArgumentNullException("XIDEGroup.IDEPanel");
            

            XIDEPopPanel.DisposeActive(); //让弹出的Group归位
            
            #region  可行的代码

            idePanel.TransLayout(() =>
            {
                var panel = this.FindSplitPanel();
                var visible = this.Visible;


                //下面的代码, 执行分离时, 留在原地的是新建的 Group, 而原Group作为被拖出的部分 —— 这种做法可以规避焦点问题
                var list2 = new List<XIDEPage>(this.m_ListPage);
                list2.Remove(page);

                //新建一个留在原位的 Group
                XIDEGroup group = (list2.Count <= 0) ? null : new XIDEGroup(idePanel, this.Alignment);
                if (group != null)
                {
                    group.m_State = this.State;
                    group.BaseParent = idePanel;
                    group.Visible = visible;
                    if (panel != null) { panel.SetChild(group); }
                }
                //if (this.Alignment == DA.Center) { this.Alignment = DA.FloatCenter; } //2020-07-30
                //this.State = DTGS.Float; //2020-07-30


                foreach (var page2 in list2)
                {
                    this.RemovePage(page2, true);
                    if (group != null) { group.AppendPage(page2, true); }
                }

                idePanel.ActiveGroup = this;
                this.ResetRect(); this.Invalidate();
                if (group != null) { group.ResetRect(); group.Invalidate(); }
            });

            return this;

            #endregion


            #region  作废的代码

            //下面的代码, 执行分离时, 拖出的是 新建的 Group —— 这会导致 焦点问题
            //IDETabGroup group = new IDETabGroup(this.IDEPanel, this.ParentSplitPanel, this.Alignment);
            //this.RemoveTabPage(page);
            //group.AppendTabPage(page);
            //return group;

            #endregion
        }






        /// <summary>
        /// 
        /// </summary>
        public virtual void ClearPages()
        {
            var list = new List<XIDEPage>(m_ListPage);
            foreach (var page in list) { RemovePage(page, false); }
            this.ResetRect(); this.Invalidate(); 
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="frame">Type: XIDEFrame</param>
        /// <returns></returns>
        public virtual XIDEPage FindPage(XIDEFrame frame)
        {
            var find = m_ListPage.FindAll(x => x.Frame == frame);
            if (find.Count <= 0) return null;
            if (find.Count == 1) return find[0];
            if (find.Count >= 2)
            {
                foreach (var page in find) { RemovePage(page, false); }
                AppendPage(find[0]);
                return find[0];
            }
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="frame">Type: XIDEFrame</param>
        public virtual void AppendPage(XIDEFrame frame)
        {
            RemovePage(frame);
            XIDEPage page = new XIDEPage();
            page.Frame = frame;
            AppendPage(page);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="page">Type: XIDEPage</param>
        public virtual void AppendPage(XIDEPage page)
        {
            AppendPage(page, true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="frame">Type: XIDEFrame</param>
        public virtual void RemovePage(XIDEFrame frame)
        {
            if (frame == null) return;
            var page = FindPage(frame);
            if (page != null) { RemovePage(page, true); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="page">Type: XIDEPage</param>
        public virtual void RemovePage(XIDEPage page)
        {
            RemovePage(page, true);
            var activePop = XIDEPopPanel.ActivePopPage;
            if (activePop == page || activePop == null) XIDEPopPanel.DisposeActive();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="page">Type: XIDEPage</param>
        /// <param name="refresh">Type: bool</param>
        protected virtual void AppendPage(XIDEPage page, bool refresh)
        {
            AppendPage(page, -1, refresh);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="page">Type: XIDEPage</param>
        /// <param name="index">Type: int</param>
        /// <param name="refresh">Type: bool</param>
        protected virtual void AppendPage(XIDEPage page, int index, bool refresh)
        {
            if (page == null || page.Frame == null) return;

            if (page.Group != null) { page.Group.RemovePage(page, true); }

            page.Group = this;
            if (index >= 0 && index < m_ListPage.Count) this.m_ListPage.Insert(index, page);
            else this.m_ListPage.Add(page);
            page.Frame.Parent = this;  //这行代码放到最后

            if (refresh) { this.ResetRect(); this.Invalidate(); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="page">Type: XIDEPage</param>
        /// <param name="refresh">Type: bool</param>
        protected virtual void RemovePage(XIDEPage page, bool refresh)
        {
            if (page == null || !m_ListPage.Contains(page)) return;

            page.Group = null;
            var frame = page.Frame;
            if (frame != null) { frame.Parent = null; frame.TryDestroy(); }
            m_ListPage.Remove(page); //这行代码放到最后


            ////执行 Frame 的资源释放 //todo: 不能在这里释放
            //if ( != null)
            //{
            //    var mode = frame.GetReleaseMode();
            //    if (mode == XIDEFrameReleaseMode.Dispose) { frame.Dispose(); }
            //}

            //执行 Group 的资源调整
            if (m_ListPage.Count <= 0) { this.Dispose(); }
            else if (refresh && !this.Disposing && !this.IsDisposed) { this.ResetRect(); this.Invalidate(); }

        }

        /// <summary>
        /// 将指定的 Page 设置为 当前Group 的激活Page
        /// <para>如果激活的 Page 选项卡没有显示, 则自动将此Page 调整为 第一个</para>
        /// </summary>
        /// <param name="page">需要激活的Page</param>
        public virtual void SetAutoActivePage(XIDEPage page)
        {
            if (!m_ListPage.Contains(page)) return;

            if (page.RectRealTitle.Width <= 0) this.SetActiveFirstPage(page);
            else this.SetActivePage(page);
        }
        /// <summary>
        /// 将指定的 Page 设置为 当前Group 的激活Page
        /// </summary>
        /// <param name="page">需要激活的Page</param>
        public virtual void SetActivePage(XIDEPage page)
        {
            if (!m_ListPage.Contains(page)) return;

            m_ActivePage = page;
            page.Frame.BringToFront();
            this.ResetRect();
            page.Frame.Visible = true;

            var idePanel = this.IDEPanel;
            if (idePanel != null) idePanel.OnLayoutChanged(EventArgs.Empty);
            this.Invalidate();
        }
        /// <summary>
        /// 将指定的 Page 设置为 当前Group 的激活Page, 并将 此Page 的位置调整到 第一位
        /// </summary>
        /// <param name="page">需要激活的Page</param>
        public virtual void SetActiveFirstPage(XIDEPage page)
        {
            if (!m_ListPage.Contains(page)) return;
            m_ListPage.Remove(page);
            m_ListPage.Insert(0, page);
            SetActivePage(page);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point">Type: Point</param>
        /// <returns></returns>
        public virtual DTGP FindTitlePageByPoint(Point point)
        {
            foreach (var page in m_ListPage)
            {
                if (page.RectRealTitle.Contains(point)) return page;
            }
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="point">Type: Point</param>
        /// <returns></returns>
        public virtual DTGP FindClosePageByPoint(Point point)
        {
            if (this.IsCenterLayout())
            {
                foreach (var page in m_ListPage)
                {
                    if (page.RectRealClose.Contains(point)) return page;
                }
            }
            else
            {
                if (RectClose.Contains(point)) return ActivePage;
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual void ReleaseSplitPanel()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) throw new ArgumentNullException("XIDEGroup.IDEPanel");

            var panel = this.FindSplitPanel();
            if (panel != null) panel.SetChild(null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual XIDEGroup ReleaseFloatForm()
        {
            XIDESplitPanel panel = this.FindSplitPanel();
            var floatForm = this.FindForm() as XIDEFloatForm;
            if (floatForm != null) { var panel2 = floatForm.SplitPanel; if (panel2 != null) { panel = panel2; } floatForm.Dispose(); }
            if (panel == null) throw new InvalidOperationException("无法确定释放浮动窗之后 XIDEGroup 应当归属的 XIDESplitPanel"); 

            var group = panel.Group;
            if (group != null && group != this) { group.MergeGroup(this); return group; }
            else { panel.Owner.ResetRect(); return this; }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: XIDEPageEventArgs</param>
        protected virtual void OnCloseClick(XIDEPageEventArgs e)
        {
            XIDEPageEventHandler handler = base.Events[m_EventCloseClick] as XIDEPageEventHandler;
            if (handler != null) handler(this, e);
            this.DoClose(e.Page);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: XIDEMenuStripEventArgs</param>
        protected virtual void OnMenuStripClick(XIDEMenuStripEventArgs e)
        {
            XIDEMenuStripEventHandler handler = base.Events[m_EventMenuStripClick] as XIDEMenuStripEventHandler;
            if (handler != null) handler(this, e);
            this.DoMenuStrip(e.Group, e.Page, e.RightButton);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected virtual void OnRivetClick(EventArgs e)
        {
            EventHandler handler = base.Events[m_EventRivetClick] as EventHandler;
            if (handler != null) handler(this, e);

            var state = this.State;
            if (state == DTGS.Expand) { this.DoCollapse(); }
            else { this.DoExpand(); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected virtual void OnNormalClick(EventArgs e)
        {
            EventHandler handler = base.Events[m_EventNormalClick] as EventHandler;
            if (handler != null) handler(this, e);
            this.DoNormal();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected virtual void OnMaximizeClick(EventArgs e)
        {
            EventHandler handler = base.Events[m_EventMaximizeClick] as EventHandler;
            if (handler != null) handler(this, e);
            this.DoMaximize();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected virtual void OnStateChanged(EventArgs e)
        {
            EventHandler handler = base.Events[m_EventStateChanged] as EventHandler;
            if (handler != null) handler(this, e);
            this.DoStateChanged();
        }

        #endregion


        #region  逻 辑 函 数

        /// <summary>
        /// 关闭当前Group 及其全部Page
        /// </summary>
        public virtual void DoCloseAll()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            idePanel.TransLayout(() =>
            {
                var listPage = new List<DTGP>(this.m_ListPage);
                foreach (var page in listPage) { RemovePage(page); }
            });
        }
        /// <summary>
        /// 关闭当前Group 的激活Page
        /// </summary>
        public virtual void DoCloseActive()
        {
            var page = this.ActivePage;
            if (page == null) return;
            this.DoClose(page);
        }
        /// <summary>
        /// 关闭当前Group 中的指定Page
        /// </summary>
        /// <param name="page">需要关闭的Page</param>
        public virtual void DoClose(DTGP page)
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            idePanel.TransLayout(() =>
            {
                RemovePage(page);
            });
        }

        /// <summary>
        /// 将当前 Group 以浮动窗体的形式展示
        /// </summary>
        public virtual void DoFloat()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            var floatForm = this.FindForm() as XIDEFloatForm;
            if (floatForm != null) return;

            idePanel.TransLayout(() =>
            {
                var rect2 = new Rectangle(100, 100, 400, 400);
                var panel = this.FindSplitPanel();
                XIDEFloatForm.FloatGroup(idePanel, this, panel, rect2);
            });
        }
        /// <summary>
        /// 将当前 Group 的激活Page 以浮动窗体的形式展示
        /// </summary>
        public virtual void DoFloatActive()
        {
            //todo
            MessageBox.Show("未实现 DoFloatActive()");
        }

        /// <summary>
        /// 对当前 Group 执行展开锚定, 本函数的反函数: DoCollapse()
        /// </summary>
        public virtual void DoExpand()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            var group = this;
            var state = this.State;
            if (state == DTGS.Expand) return;

            idePanel.TransLayout(() =>
            {
                if (state == DTGS.Popup) { XIDEPopPanel.DisposeActive(); }
                else if (state == DTGS.Float) { group = this.ReleaseFloatForm(); }

                group.m_State = DTGS.Expand;
                group.Visible = true;
                group.Focus();
            });

            var panel = group.FindSplitPanel();
            if (panel != null && panel.Owner != null) panel.Owner.ResetRect();
        }
        /// <summary>
        /// 对当前 Group 执行折叠隐藏, 本函数的反函数: DoExpand()
        /// </summary>
        public virtual void DoCollapse()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            var group = this;
            var state = group.State;
            if (state == DTGS.Collapse) return;

            idePanel.TransLayout(() =>
            {
                if (state == DTGS.Popup) { XIDEPopPanel.DisposeActive(); }
                else if (state == DTGS.Float) { group = this.ReleaseFloatForm(); }

                group.m_State = DTGS.Collapse;
                group.Visible = false;
            });

            var panel = group.FindSplitPanel();
            if (panel != null && panel.Owner != null) panel.Owner.ResetRect();
        }
        /// <summary>
        /// 如果当前 Group处于 浮动状态, 则将窗体 正常化, 本函数的反函数: DoMaximize()
        /// </summary>
        public virtual void DoNormal()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            var floatForm = this.FindForm() as XIDEFloatForm;
            if (floatForm != null) floatForm.WindowState = FormWindowState.Normal;
        }
        /// <summary>
        /// 如果当前 Group处于 浮动状态, 则将窗体 最大化, 本函数的反函数: DoNormal()
        /// </summary>
        public virtual void DoMaximize()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            var floatForm = this.FindForm() as XIDEFloatForm;
            if (floatForm != null) floatForm.WindowState = FormWindowState.Maximized;
        }


        #region  执行 IDEFloatForm 悬浮

        /// <summary>
        /// 内部字段
        /// </summary>
        protected Point m_DragTitlePoint;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected bool m_IsDragGroup;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected bool m_IsDragPage;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected DTGP m_DragPage;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected bool m_DragPageChanged;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected List<DTGPR> m_ListPageRectCache;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point">Type: Point</param>
        public void StartFloat(Point point)
        {
            m_IsDragGroup = this.RectTitle.Contains(point);
            if (m_IsDragGroup)
            {
                var popupPage = XIDEPopPanel.ActivePopPage;
                if (this.State == DTGS.Popup && popupPage != null)
                {
                    m_DragPage = popupPage;
                    m_IsDragPage = true;
                    m_IsDragGroup = false;
                    m_DragTitlePoint = point;
                    return;
                }
                else { m_DragPage = null; m_DragTitlePoint = point; return; }
            }

            var list = new List<XIDEPage>(m_ListPage);
            foreach (var page in list)
            {
                var rect = page.RectRealTitle;
                bool isDragPage = rect.Contains(point);
                if (isDragPage)
                {
                    var relaPoint = new Point(point.X - rect.X, point.Y - rect.Y); //point; 
                    m_DragPage = page;
                    m_IsDragPage = true;
                    m_DragTitlePoint = relaPoint;
                    this.SetActivePage(page);

                    var listCache = new List<DTGPR>();
                    for (int i = 0, len = list.Count; i < len; i++)
                    {
                        var page2 = list[i];
                        listCache.Add(new DTGPR(i, page2.RectRealTitle, page2));
                    }
                    m_ListPageRectCache = listCache;
                    return;
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="point">Type: Point</param>
        public void MoveFloat(Point point)
        {
            var panel = this.FindSplitPanel();

            if (m_IsDragGroup)
            {
                #region  拖拽整个Group

                XIDEFloatForm floatForm = this.FindForm() as XIDEFloatForm;
                if (floatForm != null)
                {
                    #region  如果是最大化, 则将其正常化

                    if (floatForm.WindowState == FormWindowState.Maximized)
                    {
                        var rectOld = this.RectText;
                        floatForm.WindowState = FormWindowState.Normal;
                        var rectNew = this.RectText;
                        var x = (m_DragTitlePoint.X * rectNew.Width / rectOld.Width);
                        m_DragTitlePoint = new Point(x, m_DragTitlePoint.Y);
                    }

                    #endregion

                    #region  悬浮状态, 则让窗体随控件被拖动

                    int offsetX = (point.X - m_DragTitlePoint.X);
                    int offsetY = (point.Y - m_DragTitlePoint.Y);
                    floatForm.Location = new Point(floatForm.Location.X + offsetX, floatForm.Location.Y + offsetY);
                    this.Focus();

                    #endregion
                }
                else if (!RectTitle.Contains(point))
                {
                    if (panel == null) return;

                    #region  拽出标题区, 则开始进入 悬浮状态

                    //MessageBox.Show("拖出标题区范围");
                    var idePanel = this.IDEPanel;
                    int padding = XIDEPanel.SPLIT_SIZE;
                    int offsetX = (point.X - m_DragTitlePoint.X);
                    int offsetY = (point.Y - m_DragTitlePoint.Y);
                    Rectangle rect1 = this.RectangleToScreen(new Rectangle(Point.Empty, this.Size));
                    Rectangle rect2 = new Rectangle(rect1.X - padding + offsetX, rect1.Y - padding + offsetY, rect1.Width + (padding * 2), rect1.Height + (padding * 2));
                    XIDEFloatForm.FloatGroup(idePanel, this, panel, rect2);
                    return;

                    #endregion
                }

                #endregion
            }
            else if (m_IsDragPage)
            {
                if (panel == null) return;

                #region  拖拽单个Page

                //如果本次 Page拖拽中, 改变过 Page的Index, 则将 分离区扩大: 防止 Page交换操作 误变成 拖拽悬浮操作
                bool isPopup = (this.State == DTGS.Popup && XIDEPopPanel.ActivePopPage != null);
                var rectP = isPopup ? this.RectTitle : this.RectFullTabPage;
                if (m_DragPageChanged) { rectP = new Rectangle(rectP.X - 50, rectP.Y - 40, rectP.Width + 100, rectP.Height + 80); } //大范围 防止误操作
                else { rectP = new Rectangle(rectP.X - 25, rectP.Y - 20, rectP.Width + 50, rectP.Height + 40); } //小范围 防止误操作

                var page = this.m_DragPage;
                if (!rectP.Contains(point))
                {
                    #region  拽出Page分页标题区, 则开始进入 悬浮状态

                    //MessageBox.Show("拖出Page分页标题区范围");
                    var group = SeparateGroup(page);  //这里的 group==this
                    if (group == null) return;

                    var point2 = m_DragTitlePoint;
                    var idePanel = this.IDEPanel;
                    int padding = XIDEPanel.SPLIT_SIZE;
                    int offsetX = (point.X - m_DragTitlePoint.X);
                    int offsetY = (point.Y - m_DragTitlePoint.Y);
                    Rectangle rect1 = group.RectangleToScreen(new Rectangle(Point.Empty, group.Size));
                    Rectangle rect2 = new Rectangle(rect1.X - padding + offsetX, rect1.Y - padding + offsetY, rect1.Width + (padding * 2), rect1.Height + (padding * 2));
                    EndFloat(point);

                    XIDEFloatForm.FloatGroup(idePanel, group, panel, rect2);
                    group.StartFloat(point2);
                    return;

                    #endregion
                }
                else if (!isPopup)
                {
                    #region  在Page分页标题区内拖拽, 则调整Page顺序

                    var list = new List<DTGPR>(m_ListPageRectCache);
                    foreach (var rect in list)
                    {
                        if (rect.Rect.Contains(point))
                        {
                            if (rect.Page == page && !m_DragPageChanged) { continue; }
                            int index2 = rect.Index;
                            m_ListPage.Remove(page);
                            m_ListPage.Insert(index2, page);
                            m_DragPageChanged = true;
                        }
                    }
                    this.ResetRect();
                    this.Invalidate();

                    #endregion
                }

                #endregion
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="point">Type: Point</param>
        public void EndFloat(Point point)
        {
            XIDEFloatForm floatForm = this.FindForm() as XIDEFloatForm;
            if (m_IsDragGroup && floatForm != null)
            {
                XIDETipEventArgs arg = floatForm.NewTipEventArgs();
                if (arg != null) IDEPanel.OnFloatDock(this, arg);
                floatForm.HideTipForm();
            }

            m_DragPage = null;
            m_IsDragPage = false;
            m_IsDragGroup = false;
            m_DragPageChanged = false;
            m_ListPageRectCache = null;
            m_DragTitlePoint = Point.Empty;
        }

        #endregion








        /// <summary>
        /// 弹出当前Group 的右键菜单
        /// </summary>
        /// <param name="group">需要弹出菜单的Group</param>
        /// <param name="page">菜单针对的Page (一般是 Group的焦点Page)</param>
        /// <param name="rightButton">是否是通过鼠标右键触发的本函数</param>
        public virtual void DoMenuStrip(DTG group, DTGP page, bool rightButton)
        {
            var idePanel = this.IDEPanel;
            if (idePanel != null)
            {
                var point = Win32API.GetMouseCtrlPoint((System.Windows.Forms.Control)this);
                var items = idePanel.CreateMenuItems(this, page, point, rightButton);

                if (rightButton)
                {
                    idePanel.OpenMenuStrip(this, page, point, items);
                }
                else
                {
                    var rect = this.RectMenuStrip;
                    idePanel.OpenMenuStrip(this, page, new Point(rect.X, rect.Y + rect.Height), items);
                }
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public virtual void DoStateChanged()
        {
            //var split = this.ParentSplitControl;
            //if (split != null)
            //{
            //    //split.ResetLayout();  //todo: 
            //    //if (m_IDEPanel != null) m_IDEPanel.ResetLayout();
            //}
        }


        #endregion

        

        #region  继 承 改 写

        /// <summary>
        /// 获取或设置控件内的空白。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new Padding Padding
        {
            get { return base.Padding; }
        }
        /// <summary>
        /// 获取控件内容的内部间距（以像素为单位）。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        protected override Padding DefaultPadding
        {
            get { return new Padding(1, CAPTION_HEIGHT + 1, 1, 1); }
        }
        /// <summary>
        /// 获取包含在控件内的控件的集合。
        /// <para>[已过时] IDETabGroup禁止直接使用 Controls 属性添加子控件, 请使用 AppendTabPage(*) 函数执行此操作</para>
        /// </summary>
        [Obsolete("IDETabGroup禁止直接使用 Controls 属性添加子控件, 请使用 AppendTabPage(*) 函数执行此操作", true)]
        public new ControlCollection Controls
        {
            get { return base.Controls; }
        }

        //public new System.Windows.Forms.Control Parent
        //{
        //    get { return base.Parent; }
        //    set
        //    {
        //        if (base.Parent == value) return;

        //        var old = base.Parent;
        //        if (old != null) old.Controls.Remove(this);
        //        if (old != null && old.Controls.Contains(this))
        //            throw new Exception(string.Format("当代码设置 Parent 移除 IDETabGroup 后, Parent 的 Controls 依然包含此 IDETabGroup (这可能是 .Net 底层 WinForm 的 BUG) : \r\n    Parent = {0} \r\n    IDETabGroup = {1}", old, this));

        //        base.Parent = value;
        //    }
        //}


        /// <summary>
        /// 为控件设置输入焦点。
        /// </summary>
        public new void Focus()
        {
            if (!this.IsHandleCreated || this.Disposing || this.IsDisposed) return;
            base.Focus(); 
        }
        /// <summary>
        /// 使控件的整个图面无效并导致重绘控件。
        /// </summary>
        public new void Invalidate()
        {
            if (this.Disposing || this.IsDisposed) return;
            var size = this.Size;
            var padding = this.Padding;
            this.Invalidate(new Rectangle(0, 0, size.Width, padding.Top));
            this.Invalidate(new Rectangle(0, size.Height - padding.Bottom, size.Width, padding.Bottom));
            this.Invalidate(new Rectangle(0, 0, padding.Left, size.Height));
            this.Invalidate(new Rectangle(size.Width - padding.Right, 0, size.Width, size.Height));
            //this.Invalidate();
            //this.Invalidate();
        }

        /// <summary>
        /// 引发 System.Windows.Forms.UserControl.Load 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            ResetRect();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.SizeChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            if (!this.Disposing && !this.IsDisposed) { this.ResetRect(); }
            base.OnSizeChanged(e);
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.VisibleChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (this.Visible)
            {
                this.OnSizeChanged(EventArgs.Empty);
                var level = Win32API.GetParentLevel(this);
                if (level >= 16) { Win32API.ReSetWindowPos(this.Handle); }
            }
        }


        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseMove 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            //Console.WriteLine("IDETabGroup OnMouseMove(MouseEventArgs e) : " + e.Location);
            base.OnMouseMove(e);
            if (this.Disposing || this.IsDisposed) return;

            var press = e.Button == MouseButtons.Left;

            #region  处理标题气泡

            if (!press) { InvokeToolTip(); }

            #endregion

            #region  执 行 拖 动

            if (press)
            {
                var floatForm = this.FindForm() as XIDEFloatForm;
                bool diff = (floatForm != null && floatForm.WindowState == FormWindowState.Normal) || (Math.Abs(m_DragTitlePoint.X - e.X) >= 10 || Math.Abs(m_DragTitlePoint.Y - e.Y) >= 10);
                if (diff) this.MoveFloat(e.Location);
            }

            #endregion

            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseDown 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            //Console.WriteLine("IDETabGroup OnMouseDown(MouseEventArgs e) : " + e.Location);
            base.OnMouseDown(e);
            if (this.Disposing || this.IsDisposed) return;

            XIDEPopPanel.DisposeOther(this);

            var page = FindClosePageByPoint(e.Location);
            if (page == null && e.Button == MouseButtons.Left) { this.StartFloat(e.Location); }
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseUp 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            //Console.WriteLine("IDETabGroup OnMouseUp(MouseEventArgs e) : " + e.Location);
            base.OnMouseUp(e);
            if (this.Disposing || this.IsDisposed) return;

            var page = FindClosePageByPoint(e.Location);
            if (page != null) { this.SetActivePage(page); }
            else if (e.Button == MouseButtons.Left) { this.EndFloat(e.Location); }
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseEnter 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            if (this.Disposing || this.IsDisposed) return;

            #region  处理标题气泡

            var press = MouseButtons == MouseButtons.Left;
            if (!press) { InvokeToolTip(); }

            #endregion

            this.Invalidate();
            //Console.WriteLine("OnMouseEnter(EventArgs e)");
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseLeave 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (this.Disposing || this.IsDisposed) return;
            
            #region  处理标题气泡

            var press = MouseButtons == MouseButtons.Left;
            if (!press) { InvokeToolTip(); }

            #endregion

            this.Invalidate();
            //Console.WriteLine("OnMouseLeave(EventArgs e)");
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseClick 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnClick(e);
            if (this.Disposing || this.IsDisposed) return;

            Point point1 = MousePosition;
            Point point2 = this.PointToClient(point1);
            var closePage = FindClosePageByPoint(point2);

            if (closePage != null) { OnCloseClick(new XIDEPageEventArgs(closePage)); }
            else if (RectRivet.Contains(point2)) OnRivetClick(new XIDEPageEventArgs(this.ActivePage));
            else if (RectMinMax.Contains(point2))
            {
                var floatForm = this.FindForm() as XIDEFloatForm;
                if (floatForm != null && floatForm.WindowState == FormWindowState.Normal) OnMaximizeClick(EventArgs.Empty);
                else if (floatForm != null && floatForm.WindowState == FormWindowState.Maximized) OnNormalClick(EventArgs.Empty);
            }
            else
            {
                DTGP pointPage = null;
                var list = new List<DTGP>(m_ListPage);
                foreach (var page in list)
                {
                    if (page.RectRealTitle.Contains(point2))
                    {
                        pointPage = page;
                        this.SetActivePage(page);
                    }
                }

                bool isRightButton = e.Button == MouseButtons.Right;
                if (isRightButton || RectMenuStrip.Contains(point2)) OnMenuStripClick(new XIDEMenuStripEventArgs(this, pointPage, isRightButton));
            }

        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseDoubleClick 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            if (this.Disposing || this.IsDisposed) return;

            if (RectTitle.Contains(e.Location))
            {
                var floatForm = this.FindForm() as XIDEFloatForm;
                if (floatForm != null && floatForm.WindowState == FormWindowState.Normal) { floatForm.WindowState = FormWindowState.Maximized; }
                else if (floatForm != null && floatForm.WindowState == FormWindowState.Maximized) { floatForm.WindowState = FormWindowState.Normal; }
            }
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.Enter 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);
            if (this.Disposing || this.IsDisposed) return;

            //Console.WriteLine("protected override void OnEnter(EventArgs e)");
            this.IDEPanel.ActiveGroup = this;
            XIDEPopPanel.DisposeOther(this);
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.GotFocus 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            if (this.Disposing || this.IsDisposed) return;

            //Console.WriteLine("protected override void OnGotFocus(EventArgs e)");
            this.IDEPanel.ActiveGroup = this;
            XIDEPopPanel.DisposeOther(this);
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.Leave 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            if (this.Disposing || this.IsDisposed) return;
            
            //处理了 OnEnter(EventArgs e) 后, 不要再处理 OnLeave(EventArgs e) —— 容易导致消息死循环, 这种BUG调试都调不出来
            //if (this.IDEPanel.ActiveTabGroup == this) this.IDEPanel.ActiveTabGroup = null;
            //DisposeCurrentPopGroup();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.ParentChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.ControlAdded 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.ControlEventArgs。</param>
        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);
            if (this.Disposing || this.IsDisposed) return;
            
            var ctrl = e.Control as XIDEFrame;
            if (ctrl == null) throw new Exception("只允许向 IDETabGroup 添加 IDEFrame 类型的子控件");

            var page = FindPage(ctrl);
            if (page == null) throw new Exception("IDETabGroup禁止直接使用 Controls属性 或 子控件的Parent属性 添加子控件, 请使用 AppendTabPage(*) 函数执行此操作");
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.ControlRemoved 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.ControlEventArgs。</param>
        protected override void OnControlRemoved(ControlEventArgs e)
        {
            base.OnControlRemoved(e);
            if (this.Disposing || this.IsDisposed) return;
            
            var ctrl = e.Control as XIDEFrame;
            if (ctrl == null) throw new Exception("只允许向 IDETabGroup 添加 IDEFrame 类型的子控件");

            var page = FindPage(ctrl);
            if (page == null) throw new Exception("IDETabGroup禁止直接使用 Controls属性 或 子控件的Parent属性 删除子控件, 请使用 RemoveTabPage(*) 函数执行此操作");
        }
        /// <summary>
        /// 返回包含 System.ComponentModel.Component 的名称的 System.String（如果有）。不应重写此方法。
        /// </summary>
        /// <returns>包含 System.ComponentModel.Component 的名称的 System.String（如果有）；如果 System.ComponentModel.Component 未命名，则为 null。</returns>
        public override string ToString()
        {
            return "XIDEGroup: ".PadRight(30) + this.Name;
        }
        /// <summary>
        /// 释放由 System.Windows.Forms.Control 和它的子控件占用的非托管资源，另外还可以释放托管资源。
        /// </summary>
        /// <param name="disposing">为 true 则释放托管资源和非托管资源；为 false 则仅释放非托管资源。</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                //Console.WriteLine("XIDEGroup.Dispose(): " + this.ToString());

                if (disposing)
                {
                    XIDEPopPanel.DisposeActive();
                   
                    if (m_IDEPanel != null) { m_IDEPanel.UnRegGroup(this); }  //加上这行代码后, 主窗体点击 关闭 时, FormClosingEventArgs.Cancel 不知道为什么会等于 true

                    this.BaseParent = null;
                    this.m_IDEPanel = null;
                    this.m_ActivePage = null;
                    this.m_ListPage.Clear();
                }

                base.Dispose(disposing);
                Tools.LogDebug(string.Format("XIDEGroup 销毁: Name='{0}' Text='{1}' Type='{2}' ", this.Name, this.Text, Tools.GetKnowTypeName(this.GetType())));
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "可忽略的偶发错误"); }
        }


        #endregion


        #region  控 件 重 绘

        /// <summary>
        /// 引发 System.Windows.Forms.Control.Paint 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.PaintEventArgs。</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                base.OnPaint(e);
                if (this.Disposing || this.IsDisposed) return;

                var theme = this.Theme;
                var g = e.Graphics;

                if (this.IsCenterLayout())
                    OnPaintCenterGroup(e, g, theme);
                else
                    OnPaintNoCenterGroup(e, g, theme);
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "改写 XIDEGroup.OnPaint(PaintEventArgs e) 发生错误"); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        protected virtual void OnPaintCenterGroup(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme)
        {
            bool debug = false;

            if (debug)
            {
                #region  DEBUG 重绘模式

                g.FillRectangle(new SolidBrush(this.ContainsFocus ? Color.Red : Color.RosyBrown), RectTitle);

                Point point1 = MousePosition;
                Point point2 = this.PointToClient(point1);
                bool press = MouseButtons == MouseButtons.Left;
                Color colorClose = !RectClose.Contains(point2) ? Color.Coral : (press ? Color.Brown : Color.Chocolate);
                Color colorRivet = !RectRivet.Contains(point2) ? Color.LightGreen : (press ? Color.LimeGreen : Color.SeaGreen);
                Color colorMenu = !RectMenuStrip.Contains(point2) ? Color.LightPink : (press ? Color.HotPink : Color.DeepPink);

                g.FillRectangle(new SolidBrush(colorClose), RectClose);
                g.FillRectangle(new SolidBrush(colorRivet), RectRivet);
                g.FillRectangle(new SolidBrush(colorMenu), RectMenuStrip);


                foreach (var page in m_ListPage)
                {
                    var rect1 = page.RectRealTitle;
                    var rect2 = page.RectRealClose;

                    Color color = page.Frame.BackColor;
                    Color colorPage = (rect1.Contains(point2)/* && !rect2.Contains(point2)*/) ? ((press && !rect2.Contains(point2)) ? ColorHelper.DarkDark(color) : ColorHelper.Light(color)) : color;
                    Color colorPageClose = rect2.Contains(point2) ? (press ? Color.Brown : Color.Chocolate) : Color.Coral;

                    g.FillRectangle(new SolidBrush(colorPage), rect1);
                    g.FillRectangle(new SolidBrush(colorPageClose), rect2);
                }

                #endregion
            }
            else
            {
                #region  正式重绘

                var state = this.State;
                var enable = this.Enabled;
                var point = Win32API.GetMouseCtrlPoint((System.Windows.Forms.Control)this);

                this.OnPaintGroupTitle(e, g, theme, enable, true, state, point, RectTitle, RectText);
                this.OnPaintGroupButton(e, g, theme, enable, true, state, point, RectRivet, RectMenuStrip, RectMinMax, RectClose);
                this.OnPaintGroupPages(e, g, theme, enable, true, state, point);               
                this.OnPaintGroupBorder(e, g, theme, enable, true, state, point);

                #endregion
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        protected virtual void OnPaintNoCenterGroup(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme)
        {
            bool debug = false;

            if (debug)
            {
                #region  DEBUG 重绘模式

                g.FillRectangle(new SolidBrush(this.ContainsFocus ? Color.Red : Color.RosyBrown), RectTitle);

                Point point1 = MousePosition;
                Point point2 = this.PointToClient(point1);
                bool press = MouseButtons == MouseButtons.Left;
                Color colorClose = !RectClose.Contains(point2) ? Color.Coral : (press ? Color.Brown : Color.Chocolate);
                Color colorRivet = !RectRivet.Contains(point2) ? Color.LightGreen : (press ? Color.LimeGreen : Color.SeaGreen);
                Color colorMenu = !RectMenuStrip.Contains(point2) ? Color.LightPink : (press ? Color.HotPink : Color.DeepPink);

                g.FillRectangle(new SolidBrush(colorClose), RectClose);
                g.FillRectangle(new SolidBrush(colorRivet), RectRivet);
                g.FillRectangle(new SolidBrush(colorMenu), RectMenuStrip);

                int pageCount = m_ListPage == null ? 0 : m_ListPage.Count;
                bool showTabPage = !(this.State == DTGS.Popup && XIDEPopPanel.ActivePopPage != null) && pageCount >= 2; ;
                if (showTabPage && m_ListPage != null)
                {
                    foreach (var page in m_ListPage)
                    {
                        Color color = page.Frame.BackColor;
                        Color colorPage = !page.RectRealTitle.Contains(point2) ? color : (press ? ColorHelper.DarkDark(color) : ColorHelper.Light(color));
                        g.FillRectangle(new SolidBrush(colorPage), page.RectRealTitle);
                    }
                }

                #endregion
            }
            else
            {
                #region  正式重绘

                var state = this.State;
                var enable = this.Enabled;
                var point = Win32API.GetMouseCtrlPoint((System.Windows.Forms.Control)this);

                this.OnPaintGroupTitle(e, g, theme, enable, false, state, point, RectTitle, RectText);
                this.OnPaintGroupButton(e, g, theme, enable, false, state, point, RectRivet, RectMenuStrip, RectMinMax, RectClose);
                this.OnPaintGroupPages(e, g, theme, enable, false, state, point);
                this.OnPaintGroupBorder(e, g, theme, enable, false, state, point);

                #endregion
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectTitle">Type: Rectangle</param>
        /// <param name="rectText">Type: Rectangle</param>
        protected virtual void OnPaintGroupTitle(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point, Rectangle rectTitle, Rectangle rectText)
        {
            this.OnPaintGroupTitleBack(e, g, theme, enable, center, state, point, rectTitle);
            this.OnPaintGroupTitleText(e, g, theme, enable, center, state, point, rectText);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectTitle">Type: Rectangle</param>
        protected virtual void OnPaintGroupTitleBack(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point, Rectangle rectTitle)
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            bool active = idePanel.ActiveGroup == this; //this.ContainsFocus;
            int headImgV = !enable ? 3 : (active ? 2 : 0); //没有悬浮状态 1
            SkinBorderImage_V4 headImgV4 = theme.XIDEGroup_Title_V4;
            if (headImgV4 != null && !headImgV4.IsEmpty) { headImgV4.DrawImage(g, headImgV, rectTitle); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectText">Type: Rectangle</param>
        protected virtual void OnPaintGroupTitleText(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point, Rectangle rectText)
        {
            GUIHelper.DrawStringMiddle(g, this.Text, this.Font, this.ForeColor, rectText, enable);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectRivet">Type: Rectangle</param>
        /// <param name="rectMenu">Type: Rectangle</param>
        /// <param name="rectMinMax">Type: Rectangle</param>
        /// <param name="rectClose">Type: Rectangle</param>
        protected virtual void OnPaintGroupButton(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point, Rectangle rectRivet, Rectangle rectMenu, Rectangle rectMinMax, Rectangle rectClose)
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return;

            var floatForm = FindForm() as XIDEFloatForm;
            bool press = MouseButtons == MouseButtons.Left;
            var menuPress = idePanel.MenuStripSourceControl == this;

            this.OnPaintButton(e, g, theme, enable, center, state, point, (state == DTGS.Expand ? DTGB.Expand : DTGB.Collapse), rectRivet, rectRivet.Contains(point), press);
            this.OnPaintButton(e, g, theme, enable, center, state, point, XIDEButton.Menu, rectMenu, (menuPress || rectMenu.Contains(point)), (menuPress || press));
            this.OnPaintButton(e, g, theme, enable, center, state, point, XIDEButton.Close, rectClose, rectClose.Contains(point), press);
            if (floatForm != null) this.OnPaintButton(e, g, theme, enable, center, state, point, (floatForm.WindowState == FormWindowState.Normal ? DTGB.Maximize : DTGB.Normal), rectMinMax, rectMinMax.Contains(point), press);

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        protected virtual void OnPaintGroupBorder(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point)
        {
            if (!this.BorderVisible) return;

            var borderColor = this.BorderColor;
            if (borderColor == Color.Transparent || borderColor.IsEmpty) borderColor = theme == null ? SystemColors.ActiveBorder : (this.ContainsFocus ? theme.XIDEPanel_BorderColor_Active : theme.XIDEPanel_BorderColor);

            var rect = RectBorber;
            if (rect.Width <= 0 || rect.Height <= 0) rect = new Rectangle(Point.Empty, this.Size);

            var page = this.ActivePage;
            if (page != null) { g.SetClip(page.RectRealTitle, CombineMode.Exclude); }
            GUIHelper.DrawBorder(g, borderColor, rect, true, true);
            if (page != null) { g.SetClip(page.RectRealTitle, CombineMode.Union); }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        protected virtual void OnPaintGroupPages(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point)
        {
            if (m_ListPage == null || m_ListPage.Count <= 0) return;

            var active = this.ActivePage;
            var list = new List<XIDEPage>(m_ListPage);
            list.Remove(active);
            list.Add(active);
            foreach (var page1 in list) { this.OnPaintGroupPage(e, g, theme, enable, center, page1, state, point); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        protected virtual void OnPaintGroupPage(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGP page, DTGS state, Point point)
        {
            var icon = page.Icon;
            OnPaintGroupPageBack(e, g, theme, enable, center, page, state, point, page.RectRealTitle);
            OnPaintGroupPageText(e, g, theme, enable, center, page, state, point, page.RectRealText);
            OnPaintGroupPageIcon(e, g, theme, enable, center, page, state, point, page.RectRealIcon, icon);
            OnPaintGroupPageClose(e, g, theme, enable, center, page, state, point, page.RectRealClose);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectPage">Type: Rectangle</param>
        protected virtual void OnPaintGroupPageBack(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGP page, DTGS state, Point point, Rectangle rectPage)
        {
            var active = this.ActivePage;
            bool hover = rectPage.Contains(point);
            bool select = active == page;
            bool press = (hover && MouseButtons == MouseButtons.Left);
            Rectangle rect = rectPage;
            if (!select && active != null)
            {
                var list = this.m_ListPage;
                var index1 = list == null ? -1 : list.IndexOf(page);
                var index2 = list == null ? -1 : list.IndexOf(active);
                if (index1 < index2) { rect = new Rectangle(rect.X, rect.Y, rect.Width + 1, rect.Height); }
                else if (index1 > index2) { rect = new Rectangle(rect.X - 1, rect.Y, rect.Width + 1, rect.Height); }
            }

            int headImgV = !enable ? 3 : ((press || select) ? 2 : (hover ? 1 : 0));
            SkinBorderImage_V4 headImgV4 = null;
            if (center) { headImgV4 = theme.XIDEGroup_HeadBottom_V4; }
            else { headImgV4 = theme.XIDEGroup_HeadTop_V4; }

            if (headImgV4 != null && !headImgV4.IsEmpty) { headImgV4.DrawImage(g, headImgV, rect); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectText">Type: Rectangle</param>
        protected virtual void OnPaintGroupPageText(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGP page, DTGS state, Point point, Rectangle rectText)
        {
            var rectText2 = new Rectangle(rectText.X, rectText.Y, rectText.Width + 2, rectText.Height);
            GUIHelper.DrawStringMiddle(g, page.Text, this.Font, this.ForeColor, rectText2, enable);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectIcon">Type: Rectangle</param>
        /// <param name="icon">Type: Image</param>
        protected virtual void OnPaintGroupPageIcon(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGP page, DTGS state, Point point, Rectangle rectIcon, Image icon)
        {
            if (!this.Enabled) icon = GUIHelper.CreateDisabledImage(icon);
            GUIHelper.DrawImageCenter(g, icon, rectIcon);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="rectClose">Type: Rectangle</param>
        protected virtual void OnPaintGroupPageClose(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGP page, DTGS state, Point point, Rectangle rectClose)
        {
            bool press = MouseButtons == MouseButtons.Left;
            this.OnPaintButton(e, g, theme, enable, center, state, point, XIDEButton.Close, rectClose, rectClose.Contains(point), press);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="center">Type: bool</param>
        /// <param name="state">Type: DTGS</param>
        /// <param name="point">Type: Point</param>
        /// <param name="btn">Type: XIDEButton</param>
        /// <param name="rect">Type: Rectangle</param>
        /// <param name="hover">Type: bool</param>
        /// <param name="press">Type: bool</param>
        public virtual void OnPaintButton(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, bool center, DTGS state, Point point, XIDEButton btn, Rectangle rect, bool hover, bool press)
        {
            if (rect.Width <= 0 || rect.Height <= 0) return;

            var btnV6 = theme == null ? null : theme.XIDEGroup_Button_V6;
            var btnBackV4 = theme == null ? null : theme.XIDEGroup_ButtonBack_V4;
            if (btnV6 == null || btnV6.IsEmpty) return;


            int i = (int)btn;
            int v = (!enable) ? 3 : ((press && hover) ? 2 : (hover ? 1 : 0));
            
            var imgBtn = btnV6.GetSplitYImage(i);
            if (imgBtn != null) GUIHelper.DrawImageCenter(g, imgBtn, rect);
            if (btnBackV4 != null) { btnBackV4.DrawImage(g, v, rect); }
        }

        #endregion




        #region  私 有 函 数

        /// <summary>
        /// 查找当前 Group 所属的 父级XIDESplitPanel
        /// </summary>
        /// <returns>逻辑关联的父级XIDESplitPanel</returns>
        public XIDESplitPanel FindSplitPanel()
        {
            var idePanel = this.IDEPanel;
            if (idePanel == null) return null;
            return idePanel.FindParentPanel(this);
        }


        /// <summary>
        /// 
        /// </summary>
        protected virtual void InvokeToolTip()
        {
            if (m_ListPage == null || m_ListPage.Count <= 0) return;

            var point = Win32API.GetMouseCtrlPoint((System.Windows.Forms.Control)this);
            var idePanel = this.IDEPanel;

            XIDEPage page = null;
            foreach (var temp in m_ListPage) { if (temp.RectRealTitle.Contains(point)) { page = temp; break; } }
            if (idePanel != null)
            {
                if (page != null) { idePanel.ShowToolTip(this, page, page.ToolTipText, point); }
                else { idePanel.HideToolTip(); }
            }
        }

        #endregion
    }

    /// <summary>
    /// 
    /// </summary>
    public class XIDEPage
    {
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEFrame m_Frame = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEGroup m_Group = null;

        /// <summary>
        /// 内部字段
        /// </summary>
        protected string m_Text = string.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected string m_BakText = string.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Size m_IconSize = Size.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Size m_TextSize = Size.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Size m_BakPopSize = Size.Empty;

        /// <summary>
        /// 内部字段
        /// </summary>
        protected int m_FullWidth = 0;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectRealTitle = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectRealClose = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectRealIcon = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectRealText = Rectangle.Empty;

        /// <summary>
        /// 图标
        /// </summary>
        public virtual Image Icon
        {
            get { return m_Frame == null ? null : m_Frame.Icon; }
        }
        /// <summary>
        /// 标题
        /// </summary>
        public virtual string Text
        {
            get { return m_Frame == null ? string.Empty : m_Frame.Text; }
        }
        /// <summary>
        /// 气泡提示
        /// </summary>
        public virtual string ToolTipText
        {
            get { return m_Frame == null ? string.Empty : m_Frame.ToolTipText; }
        }
        /// <summary>
        /// 当前 XIDEPage 针对的 XIDEFrame (一个XIDEPage只针对一个XIDEFrame)
        /// </summary>
        public virtual XIDEFrame Frame
        {
            get { return m_Frame; }
            set
            {
                m_Frame = value;
                m_IconSize = m_TextSize = Size.Empty; 
                ResetRect();
            }
        }
        /// <summary>
        /// 当前 XIDEPage 所属的 XIDEGroup
        /// </summary>
        public virtual XIDEGroup Group
        {
            get { return m_Group; }
            set { m_Group = value; m_IconSize = m_TextSize = Size.Empty; m_FullWidth = 0; }
        }

        /// <summary>
        /// 当 XIDEPage 在 XIDEPopPanel 中弹出时, 推荐的弹出尺寸
        /// </summary>
        public virtual Size BakPopSize
        {
            get
            {
                if (m_BakPopSize.Width <= 0 || m_BakPopSize.Height <= 0) { var group = this.Group; var list = group.ListPage; foreach (var page in list) { if (page.m_BakPopSize.Width >= 1 && page.m_BakPopSize.Height >= 1) { m_BakPopSize = page.m_BakPopSize; break; } } } //使用 同级的Page 尺寸
                if (m_BakPopSize.Width <= 0 || m_BakPopSize.Height <= 0) { var group = this.Group; if (group != null) m_BakPopSize = group.Size; } //使用 Group 尺寸
                if (m_BakPopSize.Width <= 0 || m_BakPopSize.Height <= 0) { m_BakPopSize = new Size(XIDEPanel.POP_SPLIT_PANEL_INIT_SIZE, XIDEPanel.POP_SPLIT_PANEL_INIT_SIZE); } //使用 常量尺寸
                return m_BakPopSize;
            }
            set { m_BakPopSize = new Size(Math.Max(0, value.Width), Math.Max(0, value.Height)); }
        }



        /// <summary>
        /// 
        /// </summary>
        public virtual Size IconSize
        {
            get
            {
                if (m_IconSize == Size.Empty)
                {
                    var icon = this.Icon;
                    m_IconSize = (icon != null) ? icon.Size : Size.Empty;
                    m_FullWidth = 0;
                }
                return m_IconSize;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Size TextSize
        {
            get
            {
                var text = this.Text;
                if (m_TextSize == Size.Empty || !string.Equals(m_BakText, text))
                {
                    var dockGroup = this.Group;
                    var idePanel = dockGroup == null ? null : dockGroup.IDEPanel;
                    if (idePanel != null)
                    {
                        var textSize = GUIHelper.GetStringPixel(text, idePanel.Font);
                        m_TextSize = new Size(textSize.Width + 4, textSize.Height); //2021-01-28 额外增加4像素
                        m_FullWidth = 0;
                    }
                    m_BakText = text; //当 Frame.Text 改变时, 用来清理计算的 尺寸缓存
                }
                return m_TextSize;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual int FullWidth
        {
            get
            {
                var text = this.Text;
                if (m_FullWidth <= 0 || !string.Equals(m_BakText, text))
                {
                    const int BTN_SIZE = DTG.CAPTION_BTN_SIZE;
                    var iconSize = this.IconSize;
                    var textSize = this.TextSize;
                    var fullWidth = textSize.Width + 6;
                    var dockGroup = this.Group;
                    
                    if (dockGroup != null && dockGroup.IsCenterLayout()) fullWidth = fullWidth + BTN_SIZE + 3;
                    if (iconSize.Width >= 1) fullWidth = fullWidth + iconSize.Width + 3;
                    //if (m_FullWidth != fullWidth && m_FullWidth >= 1) Console.WriteLine("FullWidth: {0} > {1}", m_FullWidth, fullWidth);
                    m_FullWidth = fullWidth;
                }
                return m_FullWidth;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectRealTitle
        {
            get { return m_RectRealTitle; }
            set
            {
                m_RectRealTitle = value;
                ResetRect();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectRealClose
        {
            get { return m_RectRealClose; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectRealIcon
        {
            get { return m_RectRealIcon; }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Rectangle RectRealText
        {
            get { return m_RectRealText; }
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual void ResetRect()
        {
            var icon = this.Icon;
            var text = this.Text;
            var iconSize = (icon != null) ? icon.Size : Size.Empty;
            if (iconSize != m_IconSize || text != m_Text) { m_Text = text; m_IconSize = iconSize; m_TextSize = Size.Empty; m_FullWidth = 0; }


            m_RectRealClose = Rectangle.Empty;
            m_RectRealIcon = Rectangle.Empty;
            m_RectRealText = Rectangle.Empty;

            var group = Group;
            var rectTitle = RectRealTitle;
            const int BTN_SIZE = DTG.CAPTION_BTN_SIZE;

            if (rectTitle.Width >= 2)
            {
                if (group != null && group.IsCenterLayout())
                    m_RectRealClose = new Rectangle(rectTitle.X + rectTitle.Width - 3 - BTN_SIZE, rectTitle.Y + (rectTitle.Height - BTN_SIZE) / 2, BTN_SIZE, BTN_SIZE);

                if (group != null)
                    m_RectRealIcon = new Rectangle(rectTitle.X + 3, rectTitle.Y + (rectTitle.Height - BTN_SIZE) / 2, iconSize.Width, iconSize.Height);

                if (group != null)
                {
                    var textWidth = rectTitle.Width - 6;
                    if (m_RectRealIcon.Width >= 1) textWidth = textWidth - m_RectRealIcon.Width - 3;
                    if (m_RectRealClose.Width >= 1) textWidth = textWidth - m_RectRealClose.Width - 3;
                    m_RectRealText = new Rectangle(m_RectRealIcon.X + m_RectRealIcon.Width + 1, rectTitle.Y + (rectTitle.Height - m_TextSize.Height) / 2, textWidth, m_TextSize.Height);
                }
            }
        }

        /// <summary>
        /// 返回表示当前 System.Object 的 System.String。
        /// </summary>
        /// <returns>System.String，表示当前的 System.Object。</returns>
        public override string ToString()
        {
            return "idePage>" + Frame;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class XIDEPageGRect
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="index">Type: int</param>
        /// <param name="rect">Type: Rectangle</param>
        /// <param name="page">Type: XIDEPage</param>
        public XIDEPageGRect(int index, Rectangle rect, XIDEPage page)
        {
            this.Index = index;
            this.Rect = rect;
            this.Page = page;
        }

        /// <summary>
        /// 
        /// </summary>
        public int Index{get;set;}
        /// <summary>
        /// 
        /// </summary>
        public Rectangle Rect{get;set;}
        /// <summary>
        /// 
        /// </summary>
        public XIDEPage Page{get;set;}
    }


    /// <summary>
    /// 
    /// </summary>
    public class XIDEMenuItemInfo
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="group">Type: XIDEGroup</param>
        /// <param name="page">Type: XIDEPage</param>
        /// <param name="item">Type: XIDEMenuItem</param>
        public XIDEMenuItemInfo(XIDEGroup group, XIDEPage page, XIDEMenuItem item)
        {
            this.Group = group;
            this.Page = page;
            this.Item = item;
        }

        /// <summary>
        /// 
        /// </summary>
        public XIDEGroup Group { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public XIDEPage Page { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public XIDEMenuItem Item { get; set; }
    }
    /// <summary>
    /// 
    /// </summary>
    public class XIDEMenuItem
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name">Type: string</param>
        /// <param name="text">Type: string</param>
        /// <param name="enabled">Type: bool</param>
        /// <param name="tag">Type: object</param>
        public XIDEMenuItem(string name, string text, bool enabled, object tag)
        {
            this.Name = name;
            this.Text = text;
            this.Enabled = enabled;
            this.Tag = tag;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name">Type: string</param>
        /// <param name="text">Type: </param>
        /// <param name="enabled">Type: bool</param>
        public XIDEMenuItem(string name, string text,bool enabled) : this(name, text, enabled, null)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name">Type: string</param>
        /// <param name="text">Type: string</param>
        public XIDEMenuItem(string name, string text) : this(name, text, true, null)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Text { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Image Icon { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public bool Enabled { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public object Tag { get; set; }
    }


    /// <summary>
    /// XIDEGroup 当前状态
    /// </summary>
    [Serializable]
    public enum XIDEGroupState
    {
        /// <summary>
        /// XIDEGroup 处于展开状态
        /// </summary>
        Expand,
        /// <summary>
        /// XIDEGroup 处于折叠状态
        /// </summary>
        Collapse,
        /// <summary>
        /// XIDEGroup 在浮动窗体中显示
        /// </summary>
        Float,
        /// <summary>
        /// XIDEGroup 是折叠状态, 但处于临时弹出可见状态
        /// </summary>
        Popup,
        /// <summary>
        /// XIDEGroup 已经被释放
        /// </summary>
        Dispose,
    }

    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public enum XIDEButton
    {
        /// <summary>
        /// 
        /// </summary>
        Menu = 0,
        /// <summary>
        /// 
        /// </summary>
        Expand = 1,
        /// <summary>
        /// 
        /// </summary>
        Collapse = 2,
        /// <summary>
        /// 
        /// </summary>
        Maximize = 3,
        /// <summary>
        /// 
        /// </summary>
        Normal = 4,
        /// <summary>
        /// 
        /// </summary>
        Close = 5,
    }



    /// <summary>
    /// System.EventArgs 是包含事件数据的类的基类。
    /// </summary>
    public class XIDEPageEventArgs : EventArgs
    {
        /// <summary>
        /// 
        /// </summary>
        public DTGP Page { get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="page">Type: DTGP</param>
        public XIDEPageEventArgs(DTGP page) { this.Page = page; }
    }
    /// <summary>
    /// System.EventArgs 是包含事件数据的类的基类。
    /// </summary>
    public class XIDEMenuStripEventArgs : EventArgs
    {
        /// <summary>
        /// 
        /// </summary>
        public DTG Group { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public DTGP Page { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public bool RightButton { get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="group">Type: DTG</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="rightButton">Type: bool</param>
        public XIDEMenuStripEventArgs(DTG group, DTGP page, bool rightButton) { this.Group = group; this.Page = page; this.RightButton = rightButton; }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender">Type: object</param>
    /// <param name="e">Type: XIDEPageEventArgs</param>
    public delegate void XIDEPageEventHandler(object sender, XIDEPageEventArgs e);
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender">Type: object</param>
    /// <param name="e">Type: XIDEMenuStripEventArgs</param>
    public delegate void XIDEMenuStripEventHandler(object sender, XIDEMenuStripEventArgs e);

}
